# -*- coding: utf-8 -*-
__author__ = 'lztkdr'
__date__ = '2020/4/15 11:31'

from sklearn import datasets as ds
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split

"""
分类算法具有的 分类指标 
"""
from sklearn.metrics import classification_report

# 多项式朴素贝叶斯
from sklearn.naive_bayes import MultinomialNB
# 高斯朴素贝叶斯
from sklearn.naive_bayes import GaussianNB
# 伯努利朴素贝叶斯
from sklearn.naive_bayes import BernoulliNB

"""
	朴素贝叶斯 算法，根据 各个类别所占比例，决定总体属于什么类别。（如 文章类别 概率，科技、金融、娱乐 一些 都在一篇文章中，哪个词频比较大，该文章就属于 哪个类别。）

	概率：定义为一件事情发生的可能性。

	朴素贝叶斯：
		使用前提：特征独立(特征与特征之间没有关联性，所以叫朴素)。
		
	朴素贝叶斯 有没有参数 提高 预测准确率呢？
		没有，朴素贝叶斯 最多只能通过 特征提取 或数据 来 提升预测准确性。	
		朴素贝叶斯 预测准确率 本身很高，就是有这样一个根本理论支持，如果 训练数据集不准确，也会影响其准确性。
	
	数据处理：
		朴素贝叶斯使用时，文本特征抽取。
	
	朴素贝叶斯分类优缺点：
		优点：
			朴素贝叶斯模型发源于古典数学理论，有稳定的分类效率。
			
			对缺失数据不太敏感，算法也比较简单，常用于文本分类。
			
			分类准确度高，速度快
		缺点：
			需要知道先验概率P(F1,F2,…|C)，因此在某些时候会由于假设的先验（假设：文章当中一些词语 与 另一些是 独立的，没有关联性，不够灵活。后面的 神经网络 会弥补该缺点，预测效果要好。）
			模型的原因导致预测效果不佳。
			
	=============================================================================
	混淆矩阵：混淆矩阵是用来总结一个分类器结果的矩阵。
	分类模型的评估:
		from sklearn.metrics import classification_report
		分类模型的评估标准一般最常见使用的是准确率（estimator.score()），即预测结果正确的百分比。
		准确率是相对所有分类结果；精确率、召回率、F1-score是相对于某一个分类的预测评估标准。 

	为什么需要这些指标？
		精确率(Precision): 预测结果为正例样本中真实为正例的比例（查得准）
		召回率(Recall): 真实为正例的样本中预测结果为正例的比例（查的全，对正样本的区分能力）
		F1-score，反映了模型的稳健型
	
	召回率的意义(应用场景)：
		产品的不合格率(不想漏掉任何一个不合格的产品，查全)；癌症预测（不想漏掉任何一个癌症患者）
		
	https://blog.csdn.net/houyanhua1/article/details/87968953
	
"""


def naivebayes():
	"""
	朴素贝叶斯
	:return:
	"""

	"""
	20个新闻组的新闻数据：
		http://qwone.com/~jason/20Newsgroups/
	20个新闻组数据集是大约20,000个新闻组文档的集合，在20个不同的新闻组中平均（几乎）划分。

	"""

	# 获取数据
	news = ds.fetch_20newsgroups(subset='all')
	print('dir:\n', dir(news), '\ntype(news.data):\n', type(news.data), '\nlen(news.data):\n', len(news.data))
	print("========================================")
	print('target:\n', news.target, '\nlen target:\n', len(news.target))
	print("========================================")
	print("news[0]:\n", news.data[0][:100], '.....')
	print("========================================")
	# print('filenames:\n', news.filenames)
	print("========================================")
	print('target_names:\n', news.target_names, '\nlen target_names:\n', len(news.target_names))
	print("========================================")

	# 传入 新闻文章list 与 新闻文章类型list
	# random_state 若为整数时，每次生成的数据都相同,若为None时，每次生成的数据都是随机，可能不一样
	x_train, x_test, y_train, y_test = train_test_split(news.data, news.target, test_size=0.25, random_state=1)

	print('type(x_train):', type(x_train), 'type(y_test):', type(y_test))

	print("========================================")
	# 对数据集进行特征抽取
	tf = TfidfVectorizer()

	# 以训练集当中的词的列表 进行每篇文章 重要性 统计 如：['a','b','c','d']
	x_train = tf.fit_transform(x_train)

	print('get_feature_names:\n', tf.get_feature_names()[:5])

	x_test = tf.transform(x_test)

	print("========================================")
	# 进行朴素贝叶斯算法的预测
	model = MultinomialNB(alpha=1.0)  # 多项式朴素贝叶斯 准确率为： 0.8429541595925297

	# mlt = BernoulliNB() # 伯努利朴素贝叶斯 准确率为： 0.6767826825127334

	# mlt = GaussianNB() # 高斯朴素贝叶斯 此处测试，占用内存很高，运行时间长，电脑卡死

	print('x_train.toarray():\n', x_train.toarray())

	print("========================================")
	model.fit(x_train, y_train)

	y_predict = model.predict(x_test)

	print("预测的文章类别为：", y_predict)
	print("========================================")
	# 得出准确率
	"""
	分类模型评估：
		estimator.score()  
		一般最常见的使用的是准确率，即预测结果正确的百分比。
	"""
	print("准确率为：", model.score(x_test, y_test))

	print("========================================")
	"""
	precision  精确率
    recall 召回率
    f1-score   得分
	support 支持该类的样本个数
	
	accuracy 准确率 
	"""
	print("每个类别的精确率和召回率：", classification_report(y_test, y_predict, target_names=news.target_names))

	return None


if __name__ == '__main__':
	# 多项式朴素贝叶斯(MultinomialNB) 示例
	naivebayes()
